package com.migraine.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
@ServerEndpoint(value = "/websocket/{uid}")//这里的uid就是用户的UID
public class WebSocketServer {
    /// 用户ID 与 Session 对应
    private static final ConcurrentMap<String, Session> mappedUserSession = new ConcurrentHashMap<>();
    /// 用户ID 与 StreamId 对应
    private static final ConcurrentMap<String, String> mappedUserStreamId = new ConcurrentHashMap<>();
    /// 用户ID 与 roomId 对应
    private static final ConcurrentMap<String, String> mappedUidRoomId = new ConcurrentHashMap<>();
    // 日志工具
    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 建立连接时调用
     *
     * @param session
     * @param config
     */
    @OnOpen
    public void onOpen(@PathParam("uid") String uid, Session session, EndpointConfig config) {
        logger.info(session + "建立了连接");
        mappedUserSession.put(uid, session);
        for (String key : mappedUserSession.keySet()) {
            logger.info("遍历map--key" + key + "    value" + mappedUserSession.get(key));
        }
    }


    /**
     * 断开连接时调用
     *
     * @param session
     */
    @OnClose
    public void onClose(@PathParam("uid") String uid, Session session) {
        logger.info(session + "断开了连接");
        String streamId = mappedUserStreamId.get(uid);
        //向其他用户宣告我已经离开房间
        JSONObject json = new JSONObject();
        json.put("type", "close");
        json.put("sourceName", uid);
        json.put("streamId", streamId);
        sendMessageToOther(session, json);

        //移除
        mappedUserSession.remove(uid);
        mappedUidRoomId.remove(uid);
        mappedUserStreamId.remove(uid);

    }


    /**
     * 消息到达时调用
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(@PathParam("uid") String uid, String message, Session session) throws IOException {
        //服务类型
        String serviceType;

        String roomId;//房间名
        String streamId;//流的编号

        String messageInfo;// 消息的具体内容

        String kickUid;// 被提出的用户

        JSONObject json = JSON.parseObject(message);
        if (json.containsKey("type")) {
            serviceType = (String) json.get("type");
            logger.info("服务类型：" + serviceType);
            switch (serviceType) {
                case "conn":
                    logger.info("conn");
                    uid = (String) json.get("uid");
                    logger.info("uid:" + uid);
                    sendMessage(session, message);// 将消息原封不动返回
                    break;
                case "room":
                    logger.info("room");
                    roomId = (String) json.get("roomId");
                    streamId = (String) json.get("streamId");
                    logger.info("房间Id" + roomId + "-流id" + streamId);
                    mappedUserStreamId.put(uid, streamId);
                    mappedUidRoomId.put(uid, roomId);
                    logger.info("列表的大小" + mappedUserSession.size());
                    //判断输入的改房间号是否存在，如果存在，将用户的id列表返回
                    if (getRoomUserNum(roomId) > 1) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("type", "room");
                        List<String> roomUserList = new ArrayList<>();
                        for (String k : mappedUidRoomId.keySet()) {
                            if (mappedUidRoomId.get(k).equals(roomId) && !k.equals(uid)) {
                                roomUserList.add(k);
                            }
                            logger.info("当前房间内成员：" + k);
                        }
                        jsonObject.put("roomUserList", roomUserList);
                        sendMessage(session, jsonObject.toJSONString());
                    }
                    break;
                case "message":
                    logger.info("message");
                    roomId = (String) json.get("roomId");
                    uid = (String) json.get("source");
                    messageInfo = (String) json.get("messageInfo");

                    if (getRoomUserNum(roomId) >= 1) {
                        JSONObject jsonObject = new JSONObject();
                        List<String> roomUserList = new ArrayList<>();
                        for (String k : mappedUidRoomId.keySet()) {
                            if (mappedUidRoomId.get(k).equals(roomId)) {
                                roomUserList.add(k);
                                logger.info("当前" + roomId + "房间内有成员：" + k);
                            }
                        }
                        long date = new Date().getTime();

                        jsonObject.put("type", "message");
                        jsonObject.put("source", uid);
                        jsonObject.put("date", date);
                        jsonObject.put("message", messageInfo);

                        //向房间内所有人(包括自己)发送此消息
                        for (String userID : roomUserList) {
                            logger.info("发送消息向" + userID);
                            sendMessage(mappedUserSession.get(userID), jsonObject.toJSONString());
                        }

                    }

                    break;
                case "kickOut":
                    logger.info("开始踢人");
                    roomId = (String) json.get("roomId");
                    kickUid = (String) json.get("kickUid");

                    logger.info("踢出房间" + roomId + "内的用户id" + kickUid);
                    String kickStreamId = mappedUserStreamId.get(kickUid);
                    //向其他用户宣告kick已经离开房间
                    JSONObject jsonObj = new JSONObject();
                    jsonObj.put("type", "close");
                    jsonObj.put("sourceName", kickUid);
                    jsonObj.put("streamId", kickStreamId);
                    sendMessageToAll(jsonObj);

                    //移除
                    mappedUserSession.remove(kickUid);
                    mappedUidRoomId.remove(kickUid);
                    mappedUserStreamId.remove(kickUid);
                    break;
                default:
                    logger.info("default转发");
                    sendUser(session, json);
                    break;
            }
        }


    }

    //向其他用户发送信息
    public void sendUser(Session session, JSONObject jsonObject) {
        String targetName = (String) jsonObject.get("userName");//接受者名称
        Session receiveSession = mappedUserSession.get(targetName);
        String sourceName = "";//发送者名称
        for (String key : mappedUserSession.keySet()) {
            if (mappedUserSession.get(key) == session) {
                sourceName = key;
                break;
            }
        }
        jsonObject.remove("userName");
        jsonObject.put("sourceName", sourceName);
        jsonObject.put("streamId", mappedUserStreamId.get(sourceName));
        try {
            sendMessage(receiveSession, jsonObject.toJSONString());
        } catch (IOException e) {
            logger.error("错误：", e);
        }

    }

    //向一个人发送消息
    public synchronized void sendMessage(Session session, String text) throws IOException {

        waitTime(100);
        session.getAsyncRemote().sendText(text);

    }

    //向除自己以外所有人发送消息
    public void sendMessageToOther(Session session, JSONObject json) {
        for (String key : mappedUserSession.keySet()) {
            Session targetSession = mappedUserSession.get(key);
            if (targetSession != session) {
                try {
                    sendMessage(targetSession, json.toJSONString());
                } catch (IOException e) {
                    logger.error("错误：", e);
                }
            }
        }
    }

    //向所有人发送消息
    public void sendMessageToAll(JSONObject json) {
        for (String key : mappedUserSession.keySet()) {
            Session targetSession = mappedUserSession.get(key);

            try {
                sendMessage(targetSession, json.toJSONString());
            } catch (IOException e) {
                logger.error("错误：", e);
            }

        }
    }


    /**
     * 发生错误时调用
     *
     * @param session
     * @param throwable
     */
    @OnError
    public void onError(@PathParam("uid") String uid, Session session, Throwable throwable) {
        logger.warn("发生错误！");
        //移除
        mappedUserSession.remove(uid);
        mappedUidRoomId.remove(uid);
        mappedUserStreamId.remove(uid);
    }

    /**
     * 获取当前房间内用户的数量
     *
     * @param roomId 房间号
     * @return int     用户数量
     */
    public int getRoomUserNum(String roomId) {
        int cnt = 0;
        for (String uid : mappedUidRoomId.keySet()) {
            if (mappedUidRoomId.get(uid).equals(roomId)) {
                cnt++;
            }
        }
        return cnt;
    }

    public void waitTime(int time) {
        long date = new Date().getTime();
        date = date + time;
        while (new Date().getTime() <= date) {
        }
    }


}
